package com.credithc.eagleeye.plugins.rabbitmq;
import org.aopalliance.aop.Advice;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.aop.framework.ProxyFactoryBean;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
 * 描 述: <br/>
 * 作 者: zhangjin<br/>
 * 创 建：2019年10月24日<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
public class EagleEyeSpringRabbitDecorator {
    final Field beforePublishPostProcessorsField;

    public EagleEyeSpringRabbitDecorator() {
        Field beforePublishPostProcessorsField = null;
        try {
            beforePublishPostProcessorsField = RabbitTemplate.class.getDeclaredField("beforePublishPostProcessors");
            beforePublishPostProcessorsField.setAccessible(true);
        } catch (NoSuchFieldException e) {
        }
        this.beforePublishPostProcessorsField = beforePublishPostProcessorsField;
    }

    /**
     * 对生产者进行装饰<br>
     * 注意：只能做插入header使用，无法确定是否发送成功，发送鹰眼的方法需要使用aop方式
     * @see EagleEyeRabbitPublishAspect
     */
    public RabbitTemplate decorateBeforePublishRabbitTemplate(RabbitTemplate rabbitTemplate) {
        if (beforePublishPostProcessorsField == null) {
            return rabbitTemplate;
        }
        Collection<MessagePostProcessor> processors;
        try {
            processors = (Collection) beforePublishPostProcessorsField.get(rabbitTemplate);
        } catch (IllegalAccessException e) {
            return rabbitTemplate;
        }
        EagleEyeBeforePublishPostProcessor eagleEyeBeforePublishPostProcessor = new EagleEyeBeforePublishPostProcessor();
        // 如果当前没有消息处理器
        if (processors == null) {
            rabbitTemplate.setBeforePublishPostProcessors(eagleEyeBeforePublishPostProcessor);
            return rabbitTemplate;
        }
        // 如果已经存在消息处理器
        for(MessagePostProcessor processor : processors) {
            if (processor instanceof EagleEyeBeforePublishPostProcessor) {
                return rabbitTemplate;
            }
        }
        // 否则就添加(由于2.1.4版本之前没有add方法，所以只能set进去)
        List<MessagePostProcessor> newProcessors = new ArrayList<>(processors.size() + 1);
        newProcessors.addAll(processors);
        newProcessors.add(eagleEyeBeforePublishPostProcessor);
        rabbitTemplate.setBeforePublishPostProcessors(newProcessors.toArray(new MessagePostProcessor[0])
        );

        //return createProxy(rabbitTemplate);
        return rabbitTemplate;
    }

    //创建RabbitTemplate代理
    //改由EagleEyeRabbitPublishAspect实现
    @Deprecated
    private RabbitTemplate createProxy(Object bean) {
        ProxyFactoryBean factory = new ProxyFactoryBean();
        factory.setProxyTargetClass(true);
        factory.addAdvice(new EagleEyeRabbitPublishAdvice());
        factory.setTarget(bean);
        return (RabbitTemplate) factory.getObject();
    }

    /**
     * 对消费者进行装饰
     */
    public SimpleRabbitListenerContainerFactory decorateSimpleRabbitListenerContainerFactory(SimpleRabbitListenerContainerFactory factory) {
        //Advice[] chain = factory.getAdviceChain();
        //由于1.7版本之前没有factory.getAdviceChain()方法，需要反射获取
        Field adviceChainField =null;
        try{
            adviceChainField = SimpleRabbitListenerContainerFactory.class.getDeclaredField("adviceChain");
        }catch(Exception ex){
            try{
                adviceChainField= AbstractRabbitListenerContainerFactory.class.getDeclaredField("adviceChain");
            }catch(Exception ex2){
            }
        }
        if (adviceChainField == null) {
            return factory;
        }

        try{
            //将字段的访问权限设为true：即去除private修饰符的影响
            adviceChainField.setAccessible(true);
            Advice[] chain= (Advice[])adviceChainField.get(factory);
            EagleEyeRabbitListenerAdvice eagleEyeRabbitListenerAdvice = new EagleEyeRabbitListenerAdvice();
            // 如果当前还没有过滤器
            if (chain == null) {
                factory.setAdviceChain(eagleEyeRabbitListenerAdvice);
                return factory;
            }
            // 如果当前已经存在鹰眼过滤器
            for(Advice advice : chain) {
                if (advice instanceof EagleEyeRabbitListenerAdvice) {
                    return factory;
                }
            }
            // 增加一个鹰眼过滤器
            Advice[] newChain = new Advice[chain.length + 1];
            System.arraycopy(chain, 0, newChain, 0, chain.length);
            newChain[chain.length] = eagleEyeRabbitListenerAdvice;
            factory.setAdviceChain(newChain);
        }catch(Exception ex){
        }
        return factory;
    }

    /**
     * 对消费者进行装饰
     */
    public SimpleMessageListenerContainer decorateSimpleRabbitListenerContainer(SimpleMessageListenerContainer container) {
        //Advice[] chain = factory.getAdviceChain();
        //由于1.7版本之前没有factory.getAdviceChain()方法，需要反射获取
        Field adviceChainField =null;
        try{
            adviceChainField = SimpleMessageListenerContainer.class.getDeclaredField("adviceChain");
        }catch(Exception ex){
            try{
                adviceChainField= AbstractMessageListenerContainer.class.getDeclaredField("adviceChain");
            }catch(Exception ex2){
            }
        }
        if (adviceChainField == null) {
            return container;
        }


        try{
            //将字段的访问权限设为true：即去除private修饰符的影响
            adviceChainField.setAccessible(true);
            Advice[] chain= (Advice[])adviceChainField.get(container);
            EagleEyeRabbitListenerAdvice eagleEyeRabbitListenerAdvice = new EagleEyeRabbitListenerAdvice();
            // 如果当前还没有过滤器
            if (chain == null) {
                container.setAdviceChain(eagleEyeRabbitListenerAdvice);
                return container;
            }
            // 如果当前已经存在鹰眼过滤器
            for(Advice advice : chain) {
                if (advice instanceof EagleEyeRabbitListenerAdvice) {
                    return container;
                }
            }
            // 增加一个鹰眼过滤器
            Advice[] newChain = new Advice[chain.length + 1];
            System.arraycopy(chain, 0, newChain, 0, chain.length);
            newChain[chain.length] = eagleEyeRabbitListenerAdvice;
            container.setAdviceChain(newChain);
        }catch(Exception ex){
        }
        return container;

    }
}
